#pragma once

// 责任链模式
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <fstream>
#include <filesystem>
#include <ctime>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
const std::string default_filepath = "./log/";
const std::string default_filename = "test.log";
static std::string delfile;
// 责任链基类
class Handler
{
public:
    virtual ~Handler() {}
    virtual void Execute(const std::string &text) = 0;
    void SetNext(std::shared_ptr<Handler> next)
    {
        _next = next;
    }
    void Enable()
    {
        _isEnable = true;
    }
    void Disable()
    {
        _isEnable = false;
    }
    virtual std::string GetCurrTime()
    {
        time_t now_time = time(nullptr);
        struct tm *curr_time = localtime(&now_time);
        // 转换为string格式
        char buf[128];
        snprintf(buf, sizeof(buf), "[%d-%02d-%02d %02d:%02d:%02d][%d]",
                 curr_time->tm_year + 1900,
                 curr_time->tm_mon + 1,
                 curr_time->tm_mday,
                 curr_time->tm_hour,
                 curr_time->tm_min,
                 curr_time->tm_sec,
                 getpid());
        return buf;
    }
protected:
    std::shared_ptr<Handler> _next;
    bool _isEnable = true;
};

// 格式化处理节点
class HandlerFormatText : public Handler
{
public:
    void Execute(const std::string &text) override
    {
        std::string formattext = text;
        if (_isEnable)
        {
            std::stringstream ss;
            ss << Handler::GetCurrTime() << text << "\n";
            formattext = ss.str();
            LOG(INFO, "格式化完毕,结果: %s\n", formattext.c_str());
        }
        if (_next)
        {
            _next->Execute(formattext);
        }
        else
        {
            LOG(DEBUG, "到达责任链结尾，本次任务处理完毕\n");
        }
    }
};
// 保存文件节点
class HandleSaveFile : public Handler
{
private:
    std::string _filepath;
    std::string _filename;

public:
    HandleSaveFile(const std::string &filepath = default_filepath, const std::string &filename = default_filename)
        : _filepath(filepath),
          _filename(filename)
    {
        if (std::filesystem::exists(_filepath))
            return;
        // 目录不存在需要创建
        CreateFilepath();
    }
    void CreateFilepath()
    {
        try
        {
            std::filesystem::create_directories(_filepath);
        }
        catch (std::filesystem::filesystem_error &error)
        {
            LOG(ERROR, "创建目录%s失败\n", error.what());
        }
    }
    void Execute(const std::string &text) override
    {
        std::string file = _filepath + _filename;
        if (_isEnable)
        {
            // 保存到文件
            std::ofstream ofs(file, std::ios::app);
            if (!ofs.is_open())
            {
                LOG(ERROR, "%s打开失败\n", file.c_str());
                return;
            }
            ofs << text;
            ofs.close();
            LOG(INFO, "保存到文件完毕\n");
        }
        if (_next)
        {
            _next->Execute(file);
        }
        else
        {
            LOG(DEBUG, "到达责任链结尾，本次任务处理完毕\n");
        }
    }
};

const int default_maxline = 5; // TODO
// 检测当前日志文件是否过大
class HandleBackUp : public Handler
{
private:
    std::string _filepath;
    std::string _filename;
    int _maxline;

public:
    HandleBackUp(const std::string &filepath = default_filepath,
                 const std::string &filename = default_filename,
                 int maxline = default_maxline)
        : _filepath(filepath),
          _filename(filename),
          _maxline(maxline)
    {
    }
    void Execute(const std::string &text) override
    {
        if (_isEnable)
        {
            std::string file = _filepath + _filename;
            if (IsOutRange(file))
            {
                // 分片保存,让子进程去做这件事！
                BackUp(file);
            }
            LOG(INFO, "分片检测处理完毕\n");
        }
        if (_next)
        {
            _next->Execute(text);
        }
        else
        {
            LOG(DEBUG, "到达责任链结尾，本次任务处理完毕\n");
        }
        return;
    }
public:
    virtual std::string GetCurrTime() override
    {
        time_t now_time = time(nullptr);
        struct tm *curr_time = localtime(&now_time);
        // 转换为string格式
        char buf[128];
        snprintf(buf, sizeof(buf), ".%d_%02d_%02d_%02d_%02d_%02d_%d",
                 curr_time->tm_year + 1900,
                 curr_time->tm_mon + 1,
                 curr_time->tm_mday,
                 curr_time->tm_hour,
                 curr_time->tm_min,
                 curr_time->tm_sec,
                 getpid());
        return buf;
    }
private:
    void BackUp(const std::string &file)
    {
        std::string suffix = GetCurrTime();
        std::string backfilename = file + "." + suffix;
        printf("文件:%s\n",backfilename.c_str());
        delfile = backfilename;
        // 注意：不能给打包文件带目录路径，即./tmp/test.log.xxx 不能携带./tmp/,只保留test.log.xxx
        std::string tgzfilesrc = _filename + "." + suffix;
        std::string tgzfiledst = tgzfilesrc + ".tgz";

        // 1.创建子进程
        pid_t pid = fork();
        if (pid == 0)
        {
            // 2.先将文件重命名
            std::filesystem::rename(file, backfilename);
            // 3.让子进程执行进程替换创建tgz格式文件备份
            std::filesystem::current_path(_filepath);
            // 进程替换执行打包命令后删除备份文件
            execlp("tar", "tar", "-czf", tgzfiledst.c_str(), tgzfilesrc.c_str(), nullptr);
            exit(1);
        }
    }
    bool IsOutRange(const std::string &file)
    {
        std::ifstream ifs(file);
        if (!ifs.is_open())
        {
            return false;
        }
        int lines = 0;
        std::string line;
        while (std::getline(ifs, line))
        {
            ++lines;
        }
        ifs.close();
        printf("lines = %d,max_line = %d\n", lines, _maxline);
        return lines > _maxline;
    }
};

// 责任链入口
class HandlerEntry
{
private:
    std::shared_ptr<HandlerFormatText> _format;
    std::shared_ptr<HandleSaveFile> _save;
    std::shared_ptr<HandleBackUp> _backup;

public:
    HandlerEntry()
    {
        // 构造责任链节点
        _format = std::make_shared<HandlerFormatText>();
        _save = std::make_shared<HandleSaveFile>();
        _backup = std::make_shared<HandleBackUp>();

        // 连接
        _format->SetNext(_save);
        _save->SetNext(_backup);

        // 避免子进程僵尸
        signal(SIGCHLD, [](int signum)
               {
                   int status = 0;
                   pid_t id = 0;
                   while ((id = (waitpid(-1, &status, WNOHANG))) > 0)
                   {
                       if (WIFEXITED(status))
                       {
                           // 父进程删除文件
                           LOG(DEBUG, "要删除的文件:%s\n", delfile.c_str());
                           std::cout << std::filesystem::remove(delfile) << std::endl;
                       }
                       else if (WIFSIGNALED(status))
                       {
                           LOG(WARNING, "子进程%d被信号 %d 终止\n", id,WTERMSIG(status));
                       }
                   } 
                });
    }

    void Run(std::string &text)
    {
        _format->Execute(text);
    }
};
